package com.jprocms.module.cms.framework.tree;

import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.jprocms.module.cms.framework.constant.CommonConstants.PATH_SPLIT;

/**
 * @author jprocms
 */
@Slf4j
public class TreePathUtil {

    /**
     * 传入id拼接成_id_对应的path
     *
     * @param id
     * @return
     */
    public static String joinPathById(Long id) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(PATH_SPLIT);
        stringBuffer.append(id.toString());
        stringBuffer.append(PATH_SPLIT);
        return stringBuffer.toString();
    }

    /**
     * 根据path 解析parentId 集合
     *
     * @param path
     * @return
     */
    public static List<Long> getParentIdsByPath(String path) {
        if (StringUtils.isBlank(path) || path.equals(PATH_SPLIT)) {
            return Collections.emptyList();
        }
        String[] paretIdStr = path.split(PATH_SPLIT);
        return Arrays.stream(paretIdStr).filter(s -> StringUtils.isNumeric(s)).map(Long::valueOf)
                .collect(Collectors.toList());
    }

    /**
     * 根据父节点生成path
     *
     * @param parent
     * @return
     */
    public static String generateChildPath(String parentPath, Long parentId) {
        if (StringUtils.isBlank(parentPath)) {
            parentPath = PATH_SPLIT;
        }
        if (parentId == null) {
            return parentPath;
        }
        return new StringBuilder(parentPath).append(parentId).append(PATH_SPLIT).toString();
    }

    /**
     * 过滤子节点
     *
     * @param parentPath 父节点path
     * @param trees      待过滤节点
     * @param <T>
     * @return
     */
    public static <T extends TreeDto> List<T> getFilterChildren(String parentPath, List<T> trees) {
        if (StringUtils.isBlank(parentPath) || CollectionUtils.isEmpty(trees)) {
            return new ArrayList<>();
        }
        if (PATH_SPLIT.equals(parentPath)) {
            return trees;
        }
        return trees.stream()
                .filter(tree -> StringUtils.isNotBlank(tree.getPath()) && tree.getPath()
                        .startsWith(parentPath)).collect(Collectors.toList());
    }

    /**
     * 转换集合 为TreeDto
     *
     * @param collection 待转换集合
     * @param comparator 排序比较器
     * @param <T>
     * @return
     */
    public static <T extends TreeDto> List<T> convertToTree(Collection<T> collection, Comparator<T> comparator) {
        if (CollectionUtil.isEmpty(collection)) {
            return Collections.emptyList();
        }
        Set<Long> ids = com.jpro.framework.common.util.collection.CollectionUtils.convertSet(collection, T::getId);
        List<T> parents = collection.stream().filter(s -> s.getParentId() == null || !ids.contains(s.getParentId())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(parents)) {
            return Collections.emptyList();
        }
        Set<Long> parentIds = com.jpro.framework.common.util.collection.CollectionUtils.convertSet(parents, T::getId);
        Map<Long, List<T>> listMap = collection.stream().filter(s -> !parentIds.contains(s.getId())).collect(Collectors.groupingBy(item -> item.getParentId()));
        parents.forEach(parentTree -> fillChildren(parentTree, listMap, comparator));
        if (comparator != null) {
            Collections.sort(parents, comparator);
        }
        return parents;
    }

    private static <T extends TreeDto> void fillChildren(T parent, Map<Long, List<T>> listMap,
                                                         Comparator<T> comparator) {
        if (parent == null || listMap.get(parent.getId()) == null) {
            return;
        }
        List<T> children = listMap.get(parent.getId());
        if (CollectionUtils.isNotEmpty(children)) {
            children.forEach(c -> fillChildren(c, listMap, comparator));
            if (comparator != null) {
                Collections.sort(children, comparator);
            }
        }
        parent.setChildren(children);
    }

    public static Long getTopId(String path) {
        if (StringUtils.isBlank(path) || path.equals(PATH_SPLIT)) {
            return null;
        }
        String[] paretIdStr = path.split(PATH_SPLIT);
        if (paretIdStr.length > 1 && StringUtils.isNumeric(paretIdStr[1])) {
            return Long.valueOf(paretIdStr[1]);
        }
        return null;
    }

}
